
#include <multimedia/imagem/Canny.h>


static const int sobelMaskX[][3] = {{-1, 0, 1},
                                    {-2, 0, 2},
                                    {-1, 0, 1}};

static const int sobelMaskY[][3] = {{ 1, 2, 1},
                                    { 0, 0, 0},
                                    {-1,-2,-1}};

void CannyFilter(Imagem& img, int lower, int upper)
{
    img.Gaussian();
    
    int**   edgeDir = (int**) ::malloc(img.Largura()*sizeof(int*));
    for(int i=0; i<img.Largura(); i++)
        edgeDir[i] = (int*) ::malloc(img.Altura()*sizeof(int));
    
    float** gradient = (float**) ::malloc(img.Largura()*sizeof(float*));
    for(int i=0; i<img.Largura(); i++)
        gradient[i] = (float*) ::malloc(img.Altura()*sizeof(float));
    
    
    for(int i=1; i<img.Largura()-1; i++)
        for(int j=1; j<img.Altura()-1; j++)
        {
            float gx = 0;
            float gy = 0;
            
            for(int p=-1; p<=1; p++)
                for(int q=-1; q<=1; q++)
                {
                    gx += (BANDA_R(img[i+p][j+q]) * sobelMaskX[p+1][q+1]);
                    gy += (BANDA_R(img[i+p][j+q]) * sobelMaskY[p+1][q+1]);
                }
                
            gradient[i][j]  = Math::sqrt(gx*gx + gy*gy);

            double direction;
            if(gy!=0)
                direction = Math::atan(((double)gx)/gy);
            else
                direction = Math::PI/2;

            if(direction > 3*Math::PI/8)
                edgeDir[i][j] = 90;
            else if(direction > Math::PI/8)
                edgeDir[i][j] = 45;
            else if(direction > -Math::PI/8)
                edgeDir[i][j] = 0;
            else if(direction > -3*Math::PI/8)
                edgeDir[i][j] = 135;
            else
                edgeDir[i][j] = 90;
        }

    for(int i=1; i<img.Largura()-1; i++)
        for(int j=1; j<img.Altura()-1; j++)
        {
            if(gradient[i][j] > 255)
            img[i][j] = RGBA(255,255,255,255);
            else
            img[i][j] = RGBA((int)gradient[i][j],(int)gradient[i][j],(int)gradient[i][j],255);
            continue;
            
            //TODO:
            //

            
            /*if(gradient[i][j] > upper)
            img[i][j] = RGBA(255,255,255,255);
            else
            img[i][j] = RGBA(0,0,0,255);
            continue;*/
                
            if(gradient[i][j] > upper)
            {
                int newX = i;
                int newY = j;

                switch(edgeDir[i][j])
                {
                case 0:
                    while(edgeDir[newX][newY] == 0 && gradient[newX][newY] > lower
                          && newX>=1 && newX < img.Largura()-1 && newY>=1 && newY < img.Altura()-1)
                    {
                        img[newX][newY] = RGBA(255,255,255,255);
                        newX++;
                    }
                    break;
                case 45:
                    while(edgeDir[newX][newY] == 45 && gradient[newX][newY] > lower
                          && newX>=1 && newX < img.Largura()-1 && newY>=1 && newY < img.Altura()-1)
                    {
                        img[newX][newY] = RGBA(255,255,255,255);
                        newX++;
                        newY++;
                    }
                    break;
                case 90:
                    while(edgeDir[newX][newY] == 90 && gradient[newX][newY] > lower
                          && newX>=1 && newX < img.Largura()-1 && newY>=1 && newY < img.Altura()-1)
                    {
                        img[newX][newY] = RGBA(255,255,255,255);
                        newY++;
                    }
                    break;
                case 135:
                    while(edgeDir[newX][newY] == 135 && gradient[newX][newY] > lower
                          && newX>=1 && newX < img.Largura()-1 && newY>=1 && newY < img.Altura()-1)
                    {
                        img[newX][newY] = RGBA(255,255,255,255);
                        newX--;
                        newY++;
                    }
                    break;
                }
            }
            else
                img[i][j] = RGBA(0,0,0,255);
        }


    /* Non-maximum Suppression */
    /*for(int i=1; i<img.Largura()-1; i++)
        for(int j=1; j<img.Altura()-1; j++)
        {
            if(BANDA_R(img[i][j]) == 255)
            {
                switch(edgeDir[i][j])
                {
                case 0:
                    ;
                    break;
                }
            }
        }*/


    for(int i=0; i<img.Largura(); i++)
        ::free(edgeDir[i]);
    ::free(edgeDir);
    
    for(int i=0; i<img.Largura(); i++)
        ::free(gradient[i]);
    ::free(gradient);
}

